home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** Program: listcontrol.c
- ** Written by: Eric Soldan
- **
- ** Copyright © 1991 Apple Computer, Inc.
- ** All rights reserved.
- */
-
- /*
- **
- ** To create a List control, you only need a single call. For example:
- **
- ** list = CLNew(rViewCtl, Resource ID of view control for List control.
- ** &viewRect, View rect of list.
- ** numRows, Number of rows to create List with.
- ** numCols, Number of columns to create List with.
- ** cellHeight,
- ** cellWidth,
- ** theLProc, Custom List procedure resource ID.
- ** window, Window to hold List control.
- ** clHScroll | blBrdr | clActive Horizontal scrollbar, active List.
- ** );
- **
-
- ** If the CLNew call succeeds, you then have a List control in your
- ** window. It will be automatically disposed of when you close the window.
- ** If you don't waht this to happen, then you can detach it from the
- ** view control which owns it. To do this, you would to the following:
- **
- ** viewCtl = CLViewFromList(theListHndl);
- ** if (viewCtl) SetCRefCon(viewCtl, nil);
- **
- ** The view control keeps a reference to the List record in the refCon.
- ** If the refCon is cleared, then the view control does nothing. So, all that
- ** is needed to detach a List record from a view control is to set the
- ** view control's refCon nil. Now if you close the window, you will still
- ** have the List record.
- **
- **
- ** To remove a List control completely from a window, just dispose of the view
- ** control that holds the List record. To do this, just do something like the below:
- **
- ** DisposeControl(CLViewFromList(theListHndl));
- **
- ** This completely disposes of the List control.
- **
- **
- ** Events for the List record are handled nearly automatically. Just make the
- ** following call:
- **
- ** CLClick(window, eventPtr, &action);
- **
- ** If the event was handled, true is returned. If the event is false, then the
- ** event doesn't belong to a List control, and further processing of the event
- ** should be done.
- */
-
-
-
- /*****************************************************************************/
-
-
-
- #ifndef __CONTROLS__
- #include <Controls.h>
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __LISTCONTROL__
- #include "ListControl.h"
- #endif
-
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
-
- #ifndef __PACKAGES__
- #include <Packages.h>
- #endif
-
- #ifndef __RESOURCES__
- #include <Resources.h>
- #endif
-
- #ifndef __UTILITIES__
- #include "Utilities.h"
- #endif
-
-
-
- /*****************************************************************************/
-
-
-
- #define kListPosTextLen 32
- #define kPrevSel 16
-
- typedef struct cdefRsrcJMP {
- long moveInst;
- long jsrInst;
- short jmpInst;
- long jmpAddress;
- } cdefRsrcJMP;
- typedef cdefRsrcJMP *cdefRsrcJMPPtr, **cdefRsrcJMPHndl;
-
-
-
- /*****************************************************************************/
-
-
-
- static long lastKeyTime;
- static char listPosText[kListPosTextLen];
- static short listPosTextLen;
- static short gViewID;
-
- static void CLBorderDraw(ListHandle listHndl);
- static pascal long CLCtl(short varCode, ControlHandle ctl, short msg, long parm);
- static pascal short MyIntlCompare(Ptr aPtr, Ptr bPtr, short aLen, short bLen);
-
- static void dummyCLActivate(Boolean active, ListHandle listHndl);
- static Boolean dummyCLClick(WindowPtr window, EventRecord *event, short *action);
- static ControlHandle dummyCLCtlHit(void);
- static Boolean dummyCLEvent(WindowPtr window, EventRecord *event, short *action);
- static ListHandle dummyCLFindActive(WindowPtr window);
- static Boolean dummyCLFindCtl(WindowPtr window, EventRecord *event, ListHandle *listHndl, ControlHandle *ctlHit);
- static ListHandle dummyCLFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl);
- static short dummyCLInsert(ListHandle listHndl, char *data, short dataLen, short row, short col);
- static Boolean dummyCLKey(WindowPtr window, EventRecord *event);
- static ControlHandle dummyCLNext(WindowPtr window, ListHandle *listHndl, ControlHandle ctl);
- static void dummyCLPrint(RgnHandle clipRgn, ListHandle listHndl, short *row, short *col, short leftEdge, Rect *drawRct);
- static short dummyCLRowOrColSearch(ListHandle listHndl, char *data, short dataLen, short row, short col);
- static void dummyCLUpdate(RgnHandle clipRgn, ListHandle list);
- static ControlHandle dummyCLViewFromList(ListHandle listHndl);
- static void dummyCLWindActivate(WindowPtr window);
-
- CLActivateProcPtr gclActivate = dummyCLActivate;
- CLClickProcPtr gclClick = dummyCLClick;
- CLCtlHitProcPtr gclCtlHit = dummyCLCtlHit;
- CLEventProcPtr gclEvent = dummyCLEvent;
- CLFindActiveProcPtr gclFindActive = dummyCLFindActive;
- CLFindCtlProcPtr gclFindCtl = dummyCLFindCtl;
- CLFromScrollProcPtr gclFromScroll = dummyCLFromScroll;
- CLInsertProcPtr gclInsert = dummyCLInsert;
- CLKeyProcPtr gclKey = dummyCLKey;
- CLNextProcPtr gclNext = dummyCLNext;
- CLPrintProcPtr gclPrint = dummyCLPrint;
- CLRowOrColSearchProcPtr gclRowOrColSearch = dummyCLRowOrColSearch;
- CLUpdateProcPtr gclUpdate = dummyCLUpdate;
- CLViewFromListProcPtr gclViewFromList = dummyCLViewFromList;
- CLWindActivateProcPtr gclWindActivate = dummyCLWindActivate;
-
- extern short gPrintPage; /* Non-zero means we are printing. */
-
-
-
- /*****************************************************************************/
-
-
-
- static ListHandle gFoundLHndl;
- /* Global value used to return info from the List control proc. */
-
- static ControlHandle gFoundViewCtl;
- /* Global value used to return info from the List control proc. */
-
-
-
- /*****************************************************************************/
- /*****************************************************************************/
- /*****************************************************************************/
-
-
-
- /* Instead of calling the functions directly, you can reference the global
- ** proc pointers that reference the functions. This keeps everything from
- ** being linked in. The default global proc pointers point to dummy functions
- ** that behave as if there aren't any list controls. The calls can still be
- ** made, yet the runtime behavior is such that it will operate as if there
- ** no instances of the List control. This allows intermediate code to access
- ** the functions or not without automatically linking in all sorts of stuff
- ** into the application that isn't desired. To change the global proc pointers
- ** so that they point to the actual functions, just call CLInitialize() once
- ** in the beginning of the application. If CLInitialize() is referenced, it will
- ** get linked in. In turn, everything that it references directly or indirectly
- ** will get linked in. */
-
- #pragma segment Controls
- void CLInitialize(void)
- {
- if (gclActivate != CLActivate) {
- gclActivate = CLActivate;
- gclClick = CLClick;
- gclCtlHit = CLCtlHit;
- gclEvent = CLEvent;
- gclFindActive = CLFindActive;
- gclFindCtl = CLFindCtl;
- gclFromScroll = CLFromScroll;
- gclInsert = CLInsert;
- gclKey = CLKey;
- gclNext = CLNext;
- gclPrint = CLPrint;
- gclRowOrColSearch = CLRowOrColSearch;
- gclUpdate = CLUpdate;
- gclViewFromList = CLViewFromList;
- gclWindActivate = CLWindActivate;
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Activate this List record. Activation is not done by calling LActivate().
- ** The active control is indicated by the 2-pixel thick border around the
- ** List control. This allows all List controls in a window to display which
- ** cells are selected. This behavior can be overridden by calling LActivate()
- ** on the List record for List controls.
- ** Human interface dictates that only at most a single List control has this
- ** active border. For this reason, this function scans for other List
- ** controls in the window and removes the border from any other that it finds. */
-
- #pragma segment Controls
- void CLActivate(Boolean active, ListHandle listHndl)
- {
- WindowPtr window, oldPort;
- ControlHandle viewCtl;
- short oldDisplay, newDisplay;
- ListHandle list;
- CLDataHndl listData;
-
- if (listHndl) {
- window = (WindowPtr)(*listHndl)->port;
- for (viewCtl = nil;;) {
- viewCtl = CLNext(window, &list, viewCtl);
- if (!viewCtl) break;
- listData = (CLDataHndl)(*viewCtl)->contrlData;
- oldDisplay = (*listData)->mode;
- newDisplay = (oldDisplay & (0xFFFF - clActive));
- if (active)
- if (list == listHndl)
- newDisplay |= clActive;
- if (oldDisplay != newDisplay) {
- (*listData)->mode = newDisplay;
- GetPort(&oldPort);
- SetPort(window);
- CLBorderDraw(list);
- SetPort(oldPort);
- }
- }
- }
- }
-
-
-
- static void dummyCLActivate(Boolean active, ListHandle listHndl)
- {
- #pragma unused (active, listHndl)
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Controls
- static void CLBorderDraw(ListHandle listHndl)
- {
- ControlHandle viewCtl;
- WindowPtr oldPort, listPort;
- short displayInfo;
- Rect rct;
- PenState oldPen;
- CLDataHndl listData;
-
- if (listHndl) {
- if (viewCtl = CLViewFromList(listHndl)) {
- GetPort(&oldPort);
- SetPort(listPort = (*listHndl)->port);
- GetPenState(&oldPen);
- PenNormal();
- listData = (CLDataHndl)(*viewCtl)->contrlData;
- displayInfo = (*listData)->mode;
- rct = (*listHndl)->rView;
- InsetRect(&rct, -1, -1);
- FrameRect(&rct);
- if (displayInfo & clShowActive) {
- rct = (*listHndl)->rView;
- InsetRect(&rct, -4, -4);
- if ((*listHndl)->vScroll)
- rct.right += 15;
- if ((*listHndl)->hScroll)
- rct.bottom += 15;
- PenSize(2, 2);
- if ((!((WindowPeek)listPort)->hilited) || (!(displayInfo & clActive)))
- PenPat((ConstPatternParam)&qd.white);
- FrameRect(&rct);
- }
- SetPenState(&oldPen);
- SetPort(oldPort);
- }
- }
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* This is called when a mouseDown occurs in the content of a window. It
- ** returns true if the mouseDown caused a List action to occur. Events
- ** that are handled include if the user clicks on a scrollbar that is
- ** associated with a List control. */
-
- #pragma segment Controls
- Boolean CLClick(WindowPtr window, EventRecord *event, short *action)
- {
- WindowPtr oldPort;
- Point mouseLoc;
- ListHandle list;
- ControlHandle ctlHit, viewCtl;
-
- if (action)
- *action = 0;
- lastKeyTime = 0;
-
- GetPort(&oldPort);
- if (!((WindowPeek)window)->hilited) return(false);
-
- SetPort(window);
- mouseLoc = event->where;
- GlobalToLocal(&mouseLoc);
-
- if (!CLFindCtl(window, event, &list, &ctlHit)) {
- /* If user didn't hit a list control, then maybe they hit a scrollbar for
- ** a list control... */
-
- if (WhichControl(mouseLoc, window, &ctlHit)) {
- /* Well, they did hit a control. Is it a scrollbar? */
-
- if (IsScrollBar(ctlHit)) {
- /* Well, it was a scrollbar, but is the scroller related to a list control? */
-
- list = CLFromScroll(ctlHit, &viewCtl);
- /* If list is nil, then the scrollbar wasn't for a list control. */
- }
- }
- }
-
- if (!list) {
- SetPort(oldPort);
- return(false);
- } /* Didn't hit list control or related scrollbar. No action taken. */
-
-
- if (CLFindActive(window) != list) { /* If not active list control, activate it. */
- CLActivate(true, list); /* Now is the active list control. */
- if (action) /* CLClick can be called again if the control */
- *action = -1; /* activates and operates with the same click. */
- }
- else {
- if (LClick(mouseLoc, event->modifiers, list))
- if (action)
- *action = 1;
- /* If double-click, then return that it was. */
- }
-
- SetPort(oldPort);
- return(true);
- }
-
-
-
- static Boolean dummyCLClick(WindowPtr window, EventRecord *event, short *action)
- {
- #pragma unused (window, event)
-
- if (action)
- *action = 0;
- return(false);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Controls
- static pascal long CLCtl(short varCode, ControlHandle ctl, short msg, long parm)
- {
- #pragma unused (varCode)
-
- Rect viewRct;
- ListHandle list;
- WindowPtr thePort;
-
- if (list = (ListHandle)GetCRefCon(ctl))
- viewRct = (*list)->rView;
- else
- SetRect(&viewRct, 0, 0, 0, 0);
-
- switch (msg) {
- case drawCntl:
- GetPort(&thePort);
- CLUpdate(thePort->visRgn, list);
- CLBorderDraw(list);
- break;
-
- case testCntl:
- if (PtInRect(*(Point *)&parm, &viewRct)) {
- gFoundViewCtl = ctl;
- gFoundLHndl = list;
- return(1);
- }
- return(0);
- break;
-
- case calcCRgns:
- case calcCntlRgn:
- if (msg == calcCRgns)
- parm &= 0x00FFFFFF;
- RectRgn((RgnHandle)parm, &viewRct);
- break;
-
- case initCntl:
- break;
-
- case dispCntl:
- if (list) {
- LDispose(list);
- DisposeHandle((Handle)(*ctl)->contrlData);
- }
- break;
-
- case posCntl:
- break;
-
- case thumbCntl:
- break;
-
- case dragCntl:
- break;
-
- case autoTrack:
- break;
- }
-
- return(0);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* The List control that was hit by calling FindControl is saved in a
- ** global variable, since the CDEF has no way of returning what kind it was.
- ** To determine that it was a List control that was hit, first call this
- ** function. The first call returns the old value in the global variable,
- ** plus it resets the global to nil. Then call FindControl(), and then
- ** call this function again. If it returns nil, then a List control
- ** wasn't hit. If it returns non-nil, then it was a List control that
- ** was hit, and specifically the one returned. */
-
- #pragma segment Controls
- ControlHandle CLCtlHit(void)
- {
- ControlHandle ctl;
-
- ctl = gFoundViewCtl;
- gFoundViewCtl = nil;
- return(ctl);
- }
-
-
-
- static ControlHandle dummyCLCtlHit(void)
- {
- return(nil);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Handle the event if it applies to the active List control. If some
- ** action occured due to the event, return true. */
-
- #pragma segment Controls
- Boolean CLEvent(WindowPtr window, EventRecord *event, short *action)
- {
- WindowPtr clickWindow;
- short actn;
-
- if (action)
- *action = 0;
-
- switch(event->what) {
-
- case mouseDown:
- if (FindWindow(event->where, &clickWindow) == inContent)
- if (window == clickWindow)
- if (((WindowPeek)window)->hilited) return(CLClick(window, event, action));
- break;
-
- case autoKey:
- case keyDown:
- if (!(event->modifiers & cmdKey)) {
- actn = CLKey(window, event);
- if (action)
- *action = actn;
- if (actn) return(true);
- }
- break;
- }
-
- return(false);
- }
-
-
-
- static Boolean dummyCLEvent(WindowPtr window, EventRecord *event, short *action)
- {
- #pragma unused (window, event)
-
- if (action)
- *action = 0;
- return(false);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Returns the active List control, if any. Unlike the TextEdit control, passing
- ** in nil doesn't return the currently active control independent of window. The
- ** only reason that the TextEdit control returns the "globally active" control is
- ** so that the TEIdle procedure can do its thing. The List control doesn't have
- ** such a thing, so there is no purpose for a "globally active" control. If the
- ** window pointer passed in is nil (requesting the "globally active" List control),
- ** we just return nil, indicating that there isn't one. */
-
- #pragma segment Controls
- ListHandle CLFindActive(WindowPtr window)
- {
- ControlHandle viewCtl;
- ListHandle list;
- short display;
- CLDataHndl listData;
-
- if (!window) return(nil);
-
- for (viewCtl = nil;;) {
- viewCtl = CLNext(window, &list, viewCtl);
- if (!viewCtl) break;
- listData = (CLDataHndl)(*viewCtl)->contrlData;
- display = (*listData)->mode;
- if (display & clActive) break;
- }
- return(list);
- }
-
-
-
- static ListHandle dummyCLFindActive(WindowPtr window)
- {
- #pragma unused (window)
- return(nil);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* This determines if a List control was clicked on directly. This does
- ** not determine if a related scrollbar was clicked on. If a List
- ** control was clicked on, then true is returned, as well as the List
- ** handle and the handle to the view control. */
-
- #pragma segment Controls
- Boolean CLFindCtl(WindowPtr window, EventRecord *event, ListHandle *listHndl, ControlHandle *ctlHit)
- {
- WindowPtr oldPort;
- Point mouseLoc;
-
- *listHndl = nil;
-
- if (window) {
- GetPort(&oldPort);
- SetPort(window);
- mouseLoc = event->where;
- GlobalToLocal(&mouseLoc);
- SetPort(oldPort);
-
- gFoundLHndl = nil;
- FindControl(mouseLoc, window, ctlHit);
- if (*listHndl = gFoundLHndl) return(true);
- }
-
- *ctlHit = nil;
- return(false);
- }
-
-
-
- static Boolean dummyCLFindCtl(WindowPtr window, EventRecord *event, ListHandle *listHndl, ControlHandle *ctlHit)
- {
- #pragma unused (window, event)
- *listHndl = nil;
- *ctlHit = nil;
- return(false);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Find the List record that is related to the indicated scrollbar. */
-
- #pragma segment Controls
- ListHandle CLFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl)
- {
- WindowPtr window;
- ControlHandle viewCtl;
- ListHandle list;
-
- *retCtl = nil;
- if (!IsScrollBar(scrollCtl)) return(nil);
-
- window = (*scrollCtl)->contrlOwner;
-
- for (*retCtl = viewCtl = nil;;) {
- viewCtl = CLNext(window, &list, viewCtl);
- if (!viewCtl) return(nil);
- list = (ListHandle)GetCRefCon(viewCtl);
- if (
- ((*list)->vScroll == scrollCtl) ||
- ((*list)->hScroll == scrollCtl)
- ) {
- *retCtl = viewCtl;
- return(list);
- }
- }
- }
-
-
-
- static ListHandle dummyCLFromScroll(ControlHandle scrollCtl, ControlHandle *retCtl)
- {
- #pragma unused (scrollCtl)
- *retCtl = nil;
- return(nil);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Insert a cell alphabetically into the list. Whichever parameter is passed in
- ** as -1, either row or column, that is the dimension that is determined. */
-
- #pragma segment Controls
- short CLInsert(ListHandle listHndl, char *data, short dataLen, short row, short col)
- {
- short loc;
- Point cell;
-
- if (!listHndl) return(-1);
-
- loc = CLRowOrColSearch(listHndl, data, dataLen, row, col);
-
- if (row == -1) {
- LAddRow(1, cell.v = loc, listHndl);
- cell.h = col;
- }
- else {
- LAddColumn(1, cell.h = loc, listHndl);
- cell.v = row;
- }
-
- LSetCell(data, dataLen, cell, listHndl);
- return(loc);
- }
-
-
-
- static short dummyCLInsert(ListHandle listHndl, char *data, short dataLen, short row, short col)
- {
- #pragma unused (listHndl, data, dataLen, row, col)
- return(0);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* See if the keypress event applies to the List control, and if it does,
- ** handle it and return true. */
-
- #pragma segment Controls
- Boolean CLKey(WindowPtr window, EventRecord *event)
- {
- ListHandle list;
- ControlHandle listCtl;
- short key, mode;
- Point cell, dcell;
- Rect bnds, visCells;
- CLDataHndl listData;
-
- if (list = CLFindActive(window)) {
-
- listCtl = CLViewFromList(list);
- listData = (CLDataHndl)(*listCtl)->contrlData;
- mode = (*listData)->mode;
- if (!(mode & clKeyPos)) return(false);
-
- bnds = (*list)->dataBounds;
- if (bnds.top == bnds.bottom) return(true);
- if (bnds.left == bnds.right) return(true);
- /* The list is empty, so whatever was typed has been "handled". */
-
- cell.h = bnds.left;
- cell.v = bnds.top;
- key = event->message & charCodeMask;
-
- if ((key >= chLeft) && (key <= chDown)) {
- if (LGetSelect(true, &cell, list))
- key -= kPrevSel;
- switch (key) {
- case chLeft - kPrevSel:
- if (cell.h > bnds.left)
- --cell.h;
- break;
- case chRight - kPrevSel:
- if (cell.h < bnds.right - 1)
- ++cell.h;
- break;
- case chUp - kPrevSel:
- if (cell.v > bnds.top)
- --cell.v;
- break;
- case chDown - kPrevSel:
- if (cell.v < bnds.bottom - 1)
- ++cell.v;
- break;
- case chLeft:
- if (bnds.top < bnds.bottom - 1) return(true);
- /* With no previous selection, if the list has
- ** more than one row, we don't know which to use.
- ** Selection is indeterminate, so do nothing. */
- cell.v = bnds.top;
- cell.h = bnds.right - 1;
- break;
- case chRight:
- if (bnds.top < bnds.bottom - 1) return(true);
- /* With no previous selection, if the list has
- ** more than one row, we don't know which to use.
- ** Selection is indeterminate, so do nothing. */
- cell.v = bnds.top;
- cell.h = bnds.left;
- break;
- case chUp:
- if (bnds.left < bnds.right - 1) return(true);
- /* With no previous selection, if the list has
- ** more than one row, we don't know which to use.
- ** Selection is indeterminate, so do nothing. */
- cell.h = bnds.left;
- cell.v = bnds.bottom - 1;
- break;
- case chDown:
- if (bnds.left < bnds.right - 1) return(true);
- /* With no previous selection, if the list has
- ** more than one row, we don't know which to use.
- ** Selection is indeterminate, so do nothing. */
- cell.h = bnds.left;
- cell.v = bnds.top;
- break;
- }
- }
- else {
- if ((bnds.right - bnds.left > 1) && (bnds.bottom - bnds.top > 1)) return(true);
- if (lastKeyTime + 45 < TickCount()) { /* Reset character collection. */
- listPosTextLen = 0;
- lastKeyTime = TickCount();
- }
- if (listPosTextLen < kListPosTextLen)
- listPosText[listPosTextLen++] = key;
- LSearch(listPosText, listPosTextLen, MyIntlCompare, &cell, list);
- /* Find the cell closest to the query test. */
- if (cell.h >= bnds.right)
- cell.h = bnds.right - 1;
- if (cell.v >= bnds.bottom)
- cell.v = bnds.bottom - 1;
- }
-
- LSetSelect(true, cell, list); /* Select cell that is closest. */
- dcell.h = bnds.left;
- dcell.v = bnds.top;
- for (;;) { /* Deselect old cells. */
- if (!LGetSelect(true, &dcell, list)) break;
- if ((dcell.h == cell.h) && (dcell.v == cell.v)) {
- if (++dcell.h >= bnds.right) {
- dcell.h = bnds.left;
- ++dcell.v;
- }
- }
- else LSetSelect(false, dcell, list);
- }
-
- visCells = (*list)->visible;
- if (PtInRect(cell, &visCells)) return(true); /* Already in view. */
-
- if (
- (key != (chDown - kPrevSel)) ||
- (cell.v < visCells.top) ||
- (cell.h < visCells.left)
- ) {
- LAutoScroll(list); /* Let List manager scroll into view. */
- return(true); /* It handles these cases correctly. */
- }
-
- LScroll(cell.h - --visCells.right, cell.v - --visCells.bottom, list);
- /* Scroll into view the way we want it done. */
-
- return(true);
- }
-
- return(false);
- }
-
-
-
- static Boolean dummyCLKey(WindowPtr window, EventRecord *event)
- {
- #pragma unused (window, event)
- return(false);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Create a new List control. See the comments at the beginning of this
- ** file for more information. Note that this function doesn't get a dummy,
- ** as you really mean to have this code if you call it. It calls CLInitialize(),
- ** just to make sure that the proc pointers are set to point to the real function,
- ** instead of the dummy functions. By having CLNew() call CLInitialize(), the
- ** application won't have to worry about calling CLInitialize(). By the time that
- ** the application is using a List control, the proc pointers will be initialized. */
-
- #pragma segment Controls
- ListHandle CLNew(short viewID, Rect *vRect, short numRows, short numCols, short cellHeight,
- short cellWidth, short theLProc, WindowPtr window, short mode)
- {
- WindowPtr oldPort;
- Rect viewRect, dataBnds;
- Point cellSize;
- ListHandle list;
- Boolean err;
- ControlHandle viewCtl;
- cdefRsrcJMPHndl cdefRsrc;
- Boolean drawIt, hScroll, vScroll;
- CLDataHndl listData;
-
- CLInitialize(); /* Make sure that this code gets linked in, in case the application
- ** is using the proc pointers. CtlHandler.c uses the proc pointers
- ** so that if the application doesn't use List controls, this code
- ** won't get linked in. */
-
- gViewID = viewID; /* Keep viewID that was passed in. */
-
- GetPort(&oldPort);
- SetPort(window);
-
- viewRect = *vRect;
- dataBnds.top = dataBnds.left = 0;
- dataBnds.right = numCols;
- dataBnds.bottom = numRows;
-
- cellSize.h = cellWidth;
- cellSize.v = cellHeight;
-
- drawIt = (mode & clDrawIt) ? 1 : 0;
- hScroll = (mode & clHScroll) ? 1 : 0;
- vScroll = (mode & clVScroll) ? 1 : 0;
- list = LNew(&viewRect, &dataBnds, cellSize, theLProc, window, drawIt, false, hScroll, vScroll);
-
- err = false;
- if (list) { /* If we were able to create the List record... */
-
- cdefRsrc = (cdefRsrcJMPHndl)GetResource('CDEF', viewID);
- (*cdefRsrc)->jmpAddress = (long)CLCtl;
- FlushInstructionCache();
- /* Make sure that instruction caches don't kill us. */
-
- viewCtl = NewControl(window, &viewRect, nil, false, 0, 0, 0,
- viewID * 16, (long)list);
- /* Use our custom view cdef. It's wierd, but it's small. */
- /* We have to create the control initially invisible because we haven't */
- /* initialized all of the data needed by the update procedure. If it */
- /* is created visible, the update procedure will be immediately called, */
- /* and this would be very bad to do until all of the data is there. */
-
- mode &= (0xFFFF - clDrawIt);
-
- if (!viewCtl)
- err = true;
- else {
- (*viewCtl)->contrlData = nil;
- if (listData = (CLDataHndl)NewHandle(sizeof(CLDataRec))) {
- (*listData)->mode = mode;
- (*listData)->txFont = window->txFont;
- (*listData)->txFace = window->txFace;
- (*listData)->txMode = window->txMode;
- (*listData)->txSize = window->txSize;
- (*viewCtl)->contrlData = (Handle)listData;
- ShowControl(viewCtl);
- /* Now that the data is initialized, we can show the control. */
- }
- else err = true;
-
- if (mode & clActive)
- CLActivate(true, list);
- }
- }
- else err = true;
-
- SetPort(oldPort);
-
- if (err) { /* Oops. Somebody wasn't happy. */
- if (viewCtl)
- DisposeControl(viewCtl);
- /* This also disposes of the List handle! */
- else
- if (list)
- LDispose(list);
- /* We have to dispose of the List handle ourselves if
- ** creating the view control failed. */
-
- list = nil; /* Return that there is no List control. */
- }
-
- return(list);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Get the next List control in the window. You pass it a control handle
- ** for the view control, or nil to start at the beginning of the window.
- ** It returns both a List handle and the view control handle for that
- ** List record. If none is found, nil is returned. This allows you to
- ** repeatedly call this function and walk through all the List controls
- ** in a window. */
-
- #pragma segment Controls
- ControlHandle CLNext(WindowPtr window, ListHandle *listHndl, ControlHandle ctl)
- {
- short defProcID;
- ResType defProcType;
- Str255 defProcName;
-
- *listHndl = nil;
- if (!window) return(nil);
-
- if (!gViewID) return(nil);
-
- if (!ctl)
- ctl = ((WindowPeek)window)->controlList;
- else
- ctl = (*ctl)->nextControl;
-
- while (ctl) {
- defProcID = !gViewID;
- GetResInfo((*ctl)->contrlDefProc, &defProcID, &defProcType, defProcName);
- if (defProcID == gViewID) {
- *listHndl = (ListHandle)GetCRefCon(ctl);
- break;
- }
- ctl = (*ctl)->nextControl;
- }
-
- return(ctl);
- }
-
-
-
- static ControlHandle dummyCLNext(WindowPtr window, ListHandle *listHndl, ControlHandle ctl)
- {
- #pragma unused (window, ctl)
- *listHndl = nil;
- return(nil);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* From the starting for or column, print as many cells as will fit into the
- ** designated rect. Pass in a starting row and column, and they will be
- ** adjusted to indicate the first cell that didn't fit into the rect. If all
- ** remaining cells were printed, the row is returned as -1. The bottom of the
- ** rect to print in is also adjusted to indicate where the actual cut-off
- ** point was. */
-
- #pragma segment Controls
- void CLPrint(RgnHandle clipRgn, ListHandle listHndl, short *row, short *col,
- short leftEdge, Rect *drawRct)
- {
- Rect dataBnds, keepView, keepVis;
- Point csize;
- short h, v;
- RgnHandle rgn;
-
- if (!listHndl) return;
-
- dataBnds = (*listHndl)->dataBounds;
- if ((*col < dataBnds.left) || (*col >= dataBnds.right))
- *col = leftEdge;
- if (*row < dataBnds.top)
- *row = dataBnds.top;
- if (*row >= dataBnds.bottom) {
- *row = -1;
- return;
- }
-
- keepView = (*listHndl)->rView;
- csize = (*listHndl)->cellSize;
- keepVis = (*listHndl)->visible;
-
- h = (drawRct->right - drawRct->left) / csize.h;
- if (!h)
- ++h;
- v = (drawRct->bottom - drawRct->top) / csize.v;
- if (!v)
- ++v;
-
- if (*col + h > dataBnds.right)
- h = dataBnds.right - *col;
- if (*row + v > dataBnds.bottom)
- v = dataBnds.bottom - *row;
-
- drawRct->bottom = drawRct->top + v * csize.v;
-
- (*listHndl)->rView = *drawRct;
- (*listHndl)->visible.right = ((*listHndl)->visible.left = *col) + h;
- (*listHndl)->visible.bottom = ((*listHndl)->visible.top = *row) + v;
-
- if (!(rgn = clipRgn)) {
- rgn = NewRgn();
- RectRgn(rgn, drawRct);
- }
- CLUpdate(rgn, listHndl);
- if (!clipRgn)
- DisposeRgn(rgn);
-
- (*listHndl)->rView = keepView;
- (*listHndl)->visible = keepVis;
-
- *col += h;
- if (*col >= dataBnds.right) {
- *col = leftEdge;
- *row += v;
- if (*row >= dataBnds.bottom)
- *row = -1;
- }
- }
-
-
-
- static void dummyCLPrint(RgnHandle clipRgn, ListHandle listHndl, short *row, short *col,
- short leftEdge, Rect *drawRct)
- {
- #pragma unused (clipRgn, listHndl, col, leftEdge, drawRct)
- *row = -1;
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Find the location in the list where the data would belong if inserted. The row
- ** and column are passed in. If either is -1, that is the dimension that will be
- ** determined and returned. */
-
- #pragma segment Controls
- short CLRowOrColSearch(ListHandle listHndl, char *data, short dataLen, short row, short col)
- {
- Rect dataBnds;
- short numCells, baseCell, iter, pow, loc, cdataLen;
- Point cell;
- Str255 cdata;
-
- if (!listHndl) return(-1);
-
- dataBnds = (*listHndl)->dataBounds;
- if (row == -1)
- numCells = dataBnds.bottom - (baseCell = dataBnds.top);
- else
- numCells = dataBnds.right - (baseCell = dataBnds.left);
- /* Get some reference info on the size/start of the list. */
-
- cell.v = cell.h = 0;
- if (numCells) {
- if (row != -1)
- cell.v = row;
- if (col != -1)
- cell.h = col;
- for (pow = 1; pow < numCells; ++iter, pow <<= 1);
- pow >>= 1; /* pow = 2^n such that pow < numCells. */
-
- for (loc = pow; pow;) { /* Do binary search for where to insert. */
- if (loc >= numCells)
- loc = numCells - 1; /* Off the end is bad. */
- if (row == -1)
- cell.v = baseCell + loc;
- else
- cell.h = baseCell + loc;
- pow >>= 1;
-
- cdataLen = 255;
- LGetCell(cdata, &cdataLen, cell, listHndl);
- /* Get cell data to compare against. */
-
- loc += (pow * IUMagString(data, cdata, dataLen, cdataLen));
- /* Adjust location based on compare result. */
- }
-
- /* The binary search got us close, but not exact. We may be off by one
- ** in either direction. (The binary search can't position in front of
- ** the first cell in the list, for example.) Do a linear compare from
- ** this point to find the correct cell we should insert in front of. */
-
- if (loc) --loc; /* Start linear search one back. */
- for (;; ++loc) {
- if (row == -1)
- cell.v = baseCell + loc;
- else
- cell.h = baseCell + loc;
- if (loc >= numCells) break;
- cdataLen = 255;
- LGetCell(cdata, &cdataLen, cell, listHndl);
- if (IUMagString(data, cdata, dataLen, cdataLen) < 1) break;
- /* If we are less than or equal to this cell, we have
- ** found our insertion point, so break. */
- }
- }
-
- if (row == -1) return(cell.v);
- else return(cell.h);
- }
-
-
-
- static short dummyCLRowOrColSearch(ListHandle listHndl, char *data, short dataLen, short row, short col)
- {
- #pragma unused (listHndl, data, dataLen, row, col)
- return(0);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Draw the List control in the correct form. */
-
- #pragma segment Controls
- void CLUpdate(RgnHandle clipRgn, ListHandle listHndl)
- {
- WindowPtr thePort, listPort;
- short txFont, txMode, txSize;
- Style txFace;
- CLDataHndl listData;
- ControlHandle ctl;
-
- if (listHndl) {
-
- if (ctl = CLViewFromList(listHndl)) {
-
- GetPort(&thePort);
-
- txFont = thePort->txFont;
- txFace = thePort->txFace;
- txMode = thePort->txMode;
- txSize = thePort->txSize;
-
- listData = (CLDataHndl)(*ctl)->contrlData;
- TextFont((*listData)->txFont);
- TextFace((*listData)->txFace);
- TextMode((*listData)->txMode);
- TextSize((*listData)->txSize);
-
- listPort = (*listHndl)->port;
- (*listHndl)->port = thePort;
- LUpdate(clipRgn, listHndl);
- (*listHndl)->port = listPort;
-
- TextFont(txFont);
- TextFace(txFace);
- TextMode(txMode);
- TextSize(txSize);
- }
- }
- }
-
-
-
- static void dummyCLUpdate(RgnHandle clipRgn, ListHandle listHndl)
- {
- #pragma unused (clipRgn, listHndl)
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* Return the control handle for the view control that owns the List
- ** record. Use this to find the view to do customizations such as changing
- ** the update procedure for this List control. */
-
- #pragma segment Controls
- ControlHandle CLViewFromList(ListHandle listHndl)
- {
- WindowPtr window;
- ControlHandle viewCtl;
- ListHandle list;
-
- if (!listHndl) return(nil);
-
- window = (WindowPtr)(*listHndl)->port;
-
- for (viewCtl = nil;;) {
- viewCtl = CLNext(window, &list, viewCtl);
- if ((!viewCtl) || (list == listHndl)) return(viewCtl);
- }
- }
-
-
-
- static ControlHandle dummyCLViewFromList(ListHandle listHndl)
- {
- #pragma unused (listHndl)
- return(nil);
- }
-
-
-
- /*****************************************************************************/
-
-
-
- /* This window is becoming active or inactive. The borders of the List
- ** controls need to be redrawn due to this. For each List control in the
- ** window, redraw the active border. */
-
- #pragma segment Controls
- void CLWindActivate(WindowPtr window)
- {
- ControlHandle viewCtl;
- ListHandle list;
-
- if (window) {
-
- for (viewCtl = nil;;) {
- viewCtl = CLNext(window, &list, viewCtl);
- if (!viewCtl) break;
- CLBorderDraw(list);
- }
-
- lastKeyTime = 0; /* Restart the entry collection for Lists. */
- }
- }
-
-
-
- static void dummyCLWindActivate(WindowPtr window)
- {
- #pragma unused (window)
- }
-
-
-
- /*****************************************************************************/
-
-
-
- #pragma segment Controls
- pascal short MyIntlCompare(Ptr aPtr, Ptr bPtr, short aLen, short bLen)
- {
- short cmp;
-
- cmp = IUMagString(aPtr, bPtr, aLen, bLen);
- if (cmp == -1) return(1);
- else return(0);
- }
-
-
-
-